/**
Copyright (c) 2013 cnova

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

library JGrid requires Collections, JWidget
    //! runtextmacro define_sparse_array("JGRIDS")

    //! textmacro refresh_visibility_mod takes P 
        if .visibility$P$ != null then
            call FogModifierStop(.visibility$P$)
            call DestroyFogModifier(.visibility$P$)
        endif
        set .visibility$P$ = CreateFogModifierRect(Player($P$), FOG_OF_WAR_VISIBLE ,.visibility, true, false) 
        call FogModifierStart(.visibility$P$)
    //! endtextmacro
    
    
    globals
        boolean INIT_FINISH = false
    endglobals

    struct JGrid
        private timer t
        private boolean timerRunning
        private camerasetup camera
        private rect center = null 
        
        private rect visibility = null
        
        private fogmodifier visibility0 = null
        private fogmodifier visibility1 = null
        private fogmodifier visibility2 = null
        private fogmodifier visibility3 = null
        private fogmodifier visibility4 = null
        private fogmodifier visibility5 = null
        private fogmodifier visibility6 = null
        private fogmodifier visibility7 = null
        private fogmodifier visibility8 = null
        private fogmodifier visibility9 = null
        private fogmodifier visibility10 = null
        private fogmodifier visibility11 = null
        
        private real minx
        private real miny
        private real maxx
        private real maxy
        readonly real centerx
        readonly real centery
        
        private HashSet widgets
        private HashSet players

        private method recreateVisibilityModifiers takes nothing returns nothing
            if .visibility != null then
                call RemoveRect(.visibility)
            endif   
            set .visibility =  Rect(.minx, .miny, .maxx, .maxy)
            //! runtextmacro refresh_visibility_mod("0")
            //! runtextmacro refresh_visibility_mod("1")
            //! runtextmacro refresh_visibility_mod("2")
            //! runtextmacro refresh_visibility_mod("3")
            //! runtextmacro refresh_visibility_mod("4")
            //! runtextmacro refresh_visibility_mod("5")
            //! runtextmacro refresh_visibility_mod("6")
            //! runtextmacro refresh_visibility_mod("7")
            //! runtextmacro refresh_visibility_mod("8")
            //! runtextmacro refresh_visibility_mod("9")
            //! runtextmacro refresh_visibility_mod("10")
            //! runtextmacro refresh_visibility_mod("11")
        endmethod
        
        static method create takes real x, real y, real width returns thistype
            local thistype this = .allocate()
            
            if INIT_FINISH == false then
                set INIT_FINISH = true
                call CreateImage("ReplaceableTextures\\CommandButtons\\BTNCrystalBall.blp" , 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0, 0, 4)  
            endif
            set .widgets = HashSet.create()
            set .players = HashSet.create()
            set .t = CreateTimer()
            set JGRIDS[GetHandleId(.t)] = this
            
            set .minx = x
            set .miny = y
            set .maxx = x+width
            set .maxy = y+width/2.0
     
            set .centerx = x+width/2.0
            set .centery = y+width/4.0
            
            set .center = Rect(.centerx, .centery, .centerx+1.0, .centery+1.0)
            call .recreateVisibilityModifiers()
 
            set .camera = CreateCameraSetup()
            call CameraSetupSetField(.camera,CAMERA_FIELD_ZOFFSET,.0,.0)
            call CameraSetupSetField(.camera,CAMERA_FIELD_ROTATION,90.,.0)
            call CameraSetupSetField(.camera,CAMERA_FIELD_ANGLE_OF_ATTACK,270.,.0)
            call CameraSetupSetField(.camera,CAMERA_FIELD_ROLL,.0,.0)
            call CameraSetupSetField(.camera,CAMERA_FIELD_FIELD_OF_VIEW,70.,.0)
            call CameraSetupSetField(.camera,CAMERA_FIELD_FARZ, width+1000.0,.0)
            call CameraSetupSetField(.camera,CAMERA_FIELD_TARGET_DISTANCE,width,.0)
            
            //call CameraSetupSetField(.camera,CAMERA_FIELD_TARGET_DISTANCE,.maxx-.minx,.0)
            //call CameraSetupSetField(.camera,CAMERA_FIELD_FARZ,2500.,.0)
            return this
        endmethod
        
        private static method LockCamCallback takes nothing returns nothing
            local timer t = GetExpiredTimer()
            local integer i = 0
            local thistype this = JGRIDS[GetHandleId(GetExpiredTimer())]
            local player p
            
            if .players.size == 0 then
                call PauseTimer(t)
                set t = null
                set .timerRunning = false
                return
            endif
            
            loop
                exitwhen i > 11
                if .players.contains(i) then
                    // set zoom based on factor
                    // position center is also based on factor
                    // set angle to zenith
                    set p = Player(i)
                    if GetLocalPlayer() == p then
                        call SetCameraPosition(.centerx,.centery)
                        call CameraSetupApply(.camera, false, false)
                    endif
                endif
                set i = i + 1
            endloop
            set t = null
            set p = null
        endmethod
        
        method lockCam takes player p , boolean lock returns nothing
            if p == null then
                if lock then
                    call .players.add(0)
                    call .players.add(1)
                    call .players.add(2)
                    call .players.add(3)
                    call .players.add(4)
                    call .players.add(5)
                    call .players.add(6)
                    call .players.add(7)
                    call .players.add(8)
                    call .players.add(9)
                    call .players.add(10)
                    call .players.add(11)
                    call SetCameraBoundsToRect(.center)
                else
                    call .players.clear()
                    call ResetToGameCamera( 0 )
                    call SetCameraBoundsToRect(GetWorldBounds())
                endif
            else
                if lock then
                    call .players.add(GetPlayerId(p))
                    call SetCameraBoundsToRectForPlayerBJ(p, .center)
                else
                    call .players.remove(GetPlayerId(p))
                    call ResetToGameCameraForPlayer( p, 0 )
                    call SetCameraBoundsToRectForPlayerBJ(p, GetWorldBounds())
                endif
            endif
            
            if not .timerRunning and lock then
                set .timerRunning = true
                call TimerStart(.t, 0.1, true, function thistype.LockCamCallback)
            endif
            set p = null
        endmethod

        method addWidget takes JWidget w, integer x, integer y returns boolean
            local boolean added = false
            if w.canvas == 0 then
                set w.canvas = this
                call .widgets.add(w)
                set w.x = this.minx + I2R(x)
                set w.y = this.miny + I2R(y)
                call w.render()
                set added = true
            endif
            return added
        endmethod
        
        method removeWidget takes JWidget w returns boolean
            local boolean removed = false
            local JWidget toRemove = w
            if toRemove != 0 and toRemove.canvas == this then
                set toRemove.canvas = 0
                call .widgets.remove(toRemove)
                call toRemove.setVisible(false)
                set removed = true
            endif
            return removed
        endmethod
        
        // DEPRECATED FOR NOW
        method setPosition takes real x, real y returns nothing
            local Iterator it = .widgets.iterator()
            local JWidget w
            local real diffx = maxx - minx
            local real diffy = maxy - miny
            
            //TODO coordinates need to be renewed with proportion to dimensions
            set .minx = x
            set .miny = y
            set .maxx = x+diffx
            set .maxy = y+diffy
            
            set .centerx = x
            set .centery = y
            
            if .center != null then
                call RemoveRect(.center)
            endif   
            set .center = Rect(.centerx, .centery, .centerx+1.0, .centery+1.0)
            
            call .recreateVisibilityModifiers()
            
            loop
                exitwhen it.end
                set w = it.next()
                set w.x = w.x + .minx
                set w.y = w.y + .miny
                call w.render()
            endloop
        endmethod
    endstruct
endlibrary